﻿# coding: utf-8
import sys
import wx
import wx.lib.filebrowsebutton as filebrowse
import wx.lib.agw.genericmessagedialog as GMD

class IGameFileDropTarget(wx.FileDropTarget):
    def __init__(self):
        wx.FileDropTarget.__init__(self)

    def OnDropFiles(self, x, y, filenames):
        wx.GetApp()._mainFrame.OnDropIGameFileList(set(filenames))
                
class wxMainFrame(wx.Frame):    
    def __init__(self):
        wx.Frame.__init__(self, None, -1, u'wxIGameConverter', size = (800, 600), style = wx.DEFAULT_FRAME_STYLE)
        
        splitter = wx.SplitterWindow(self)
        
        # Export setting panel
        settingPanel = wx.Panel(splitter)
        self._dbbResDir = filebrowse.DirBrowseButton(
            settingPanel, -1, changeCallback = self.__OnResDirChanged,
            newDirectory = True,
            labelText = u'Resource Directory:',
            buttonText = u'Browse',
            startDirectory = GLOBAL_SETTING._resourceDir)

        self._dbbModelDir = filebrowse.DirBrowseButton(
            settingPanel, -1, changeCallback = self.__OnModelDirChanged,
            newDirectory = True,
            labelText = u'Model Directory:',
            buttonText = u'Browse',
            startDirectory = GLOBAL_SETTING._modelDir)    
                    
        self._dbbMeshDir = filebrowse.DirBrowseButton(
            settingPanel, -1, changeCallback = self.__OnMeshDirChanged,
            newDirectory = True,
            labelText = u'Mesh Directory:',
            buttonText = u'Browse',
            startDirectory = GLOBAL_SETTING._meshDir)    

        self._dbbMtlDir = filebrowse.DirBrowseButton(
            settingPanel, -1, changeCallback = self.__OnMtlDirChanged,
            newDirectory = True,
            labelText = u'Material Directory:',
            buttonText = u'Browse',
            startDirectory = GLOBAL_SETTING._materialDir)

        self._dbbAniDir = filebrowse.DirBrowseButton(
            settingPanel, -1, changeCallback = self.__OnAniDirChanged,
            newDirectory = True,
            labelText = u'Animation Directory:',
            buttonText = u'Browse',
            startDirectory = GLOBAL_SETTING._animationDir)    
        
        self._dbbTextureDir = filebrowse.DirBrowseButton(
            settingPanel, -1, changeCallback = self.__OnTextureDirChanged,
            newDirectory = True,
            style = wx.TAB_TRAVERSAL|wx.DD_DEFAULT_STYLE,
            labelText = u'Texture Directory',
            buttonText = u'Browse',
            startDirectory = GLOBAL_SETTING._textureDir)

        self._ckMeshBone = wx.CheckBox(settingPanel, -1, u'Treat others as Bone')
        self._editMeshBoneList = wx.TextCtrl(settingPanel, -1)
        sizerMeshBone = wx.BoxSizer(wx.HORIZONTAL)
        sizerMeshBone.Add(self._ckMeshBone, 0, wx.EXPAND|wx.ALL, border = 5)  
        sizerMeshBone.Add(self._editMeshBoneList, 1, wx.EXPAND|wx.ALL, border = 5)
        
        bnExport = wx.Button(settingPanel, -1, u'Export Model')
        self.Bind(wx.EVT_BUTTON, self.__OnBnExportClick, bnExport)
        
        self._logWin = wx.TextCtrl(settingPanel, -1, style = wx.TE_MULTILINE|wx.TE_READONLY)    
        self._logWin.Bind(wx.EVT_RIGHT_DOWN, self.__OnLogRightDown)
        self._idMenuLogClear = wx.NewId()
        self.Bind(wx.EVT_MENU, self.__OnMenuLogClear, id = self._idMenuLogClear)
        
        self._progressBar = wx.Gauge(settingPanel, -1, 100, (110, 50), (250, 25))   
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self._dbbResDir, 0, wx.EXPAND|wx.ALL, border = 5)
        sizer.Add(self._dbbModelDir, 0, wx.EXPAND|wx.ALL, border = 5)
        sizer.Add(self._dbbMeshDir, 0, wx.EXPAND|wx.ALL, border = 5)   
        sizer.Add(self._dbbMtlDir, 0, wx.EXPAND|wx.ALL, border = 5)   
        sizer.Add(self._dbbAniDir, 0, wx.EXPAND|wx.ALL, border = 5)  
        sizer.Add(self._dbbTextureDir, 0, wx.EXPAND|wx.ALL, border = 5)
        sizer.Add(sizerMeshBone, 0, wx.EXPAND|wx.ALL, border = 5) 
        sizer.Add(bnExport, 0, wx.CENTER, border = 5)
        sizer.Add(self._logWin, 1, wx.EXPAND|wx.ALL, border = 5)
        sizer.Add(self._progressBar, 0, wx.EXPAND|wx.ALL, 5)
        settingPanel.SetSizer(sizer)
        
        # IGame XML list and material list
        subSplitter = wx.SplitterWindow(splitter, style = wx.SP_3DSASH)
        
        self._listIGameXML = wx.ListCtrl(subSplitter, style = wx.LC_REPORT|wx.NO_BORDER)
        self._listIGameXML.InsertColumn(0, u'IGame XML File', width = 300)
        self._listIGameXML.SetDropTarget(IGameFileDropTarget())
        self.Bind(wx.EVT_LIST_KEY_DOWN, self.__OnListKeyDown, self._listIGameXML)
        
        self._listTexSearchDir = wx.ListCtrl(subSplitter, style = wx.LC_REPORT|wx.NO_BORDER)
        self._listTexSearchDir.InsertColumn(0, u'Texture File Search Directories', width = 300)
        self._listTexSearchDir.Bind(wx.EVT_LIST_KEY_DOWN, self.__OnListKeyDown)
        self._listTexSearchDir.Bind(wx.EVT_RIGHT_DOWN, self.__OnListMouseRightDown)
        self.__DefineTexSearchDirPopupMenu()
        for tsDir in GLOBAL_SETTING._texSearchDirectories:
            self._listTexSearchDir.InsertStringItem(self._listTexSearchDir.GetItemCount(), tsDir)
        
        # Setup the sub splitter
        subSplitter.SetMinimumPaneSize(200)
        subSplitter.SplitHorizontally(self._listIGameXML, self._listTexSearchDir, 200)
        
        # Setup the splitter
        splitter.SetMinimumPaneSize(200)
        splitter.SplitVertically(subSplitter, settingPanel, 320)
        
        self.Bind(wx.EVT_CLOSE, self.__OnClose)     
        
        self.UpdateUI()
        sys.stdout = sys.stderr = self._logWin
        
    def __DefineTexSearchDirPopupMenu(self):
        self._idMenuAddTexSearchDir = wx.NewId()
        self.Bind(wx.EVT_MENU, self.__OnMenuAddTextureSearchDirectory, id = self._idMenuAddTexSearchDir)
        
    def __OnListMouseRightDown(self, e):
        menu = wx.Menu()
        menu.Append(self._idMenuAddTexSearchDir, u'Add texture search directory...')
        self._listTexSearchDir.PopupMenu(menu)
        menu.Destroy()            
        
    def __OnMenuAddTextureSearchDirectory(self, e):
        directory = None
        dlg = wx.DirDialog(self, style=wx.DD_DEFAULT_STYLE)
        if dlg.ShowModal() == wx.ID_OK:
            directory = dlg.GetPath()
        dlg.Destroy()
        
        if directory and self._listTexSearchDir.FindItem(0, directory) == -1:
            self._listTexSearchDir.InsertStringItem(self._listTexSearchDir.GetItemCount(), directory)     
            GLOBAL_SETTING._texSearchDirectories.append(directory)   
        
    def __OnClose(self, e):
        self.Destroy()      
        
    def __OnLogRightDown(self, e):
        menu = wx.Menu()
        menu.Append(self._idMenuLogClear, u'Clear All')
        self.PopupMenu(menu)
        menu.Destroy()

    def __OnMenuLogClear(self, e):
        self._logWin.SetValue('')
        
    def __OnResDirChanged(self, e):
        v = self._dbbResDir.GetValue().replace('/', '\\')
        if not v.endswith('\\'):
            v += '\\'
        GLOBAL_SETTING._resourceDir = v
        
    def __OnModelDirChanged(self, e):
        v = self._dbbModelDir.GetValue().replace('/', '\\')
        if not v.endswith('\\'):
            v += '\\'
        GLOBAL_SETTING._modelDir = v

    def __OnMeshDirChanged(self, e):
        v = self._dbbMeshDir.GetValue().replace('/', '\\')
        if not v.endswith('\\'):
            v += '\\'
        GLOBAL_SETTING._meshDir = v
        
    def __OnMtlDirChanged(self, e):
        v = self._dbbMtlDir.GetValue().replace('/', '\\')
        if not v.endswith('\\'):
            v += '\\'
        GLOBAL_SETTING._materialDir = v
        
    def __OnAniDirChanged(self, e):
        v = self._dbbAniDir.GetValue().replace('/', '\\')
        if not v.endswith('\\'):
            v += '\\'
        GLOBAL_SETTING._animationDir = v

    def __OnTextureDirChanged(self, e):
        v = self._dbbTextureDir.GetValue().replace('/', '\\')
        if not v.endswith('\\'):
            v += '\\'
        GLOBAL_SETTING._textureDir = v
        
    def __CheckSetting(self):
        if self._listIGameXML.GetItemCount() == 0:
            return u'IGame XML list is empty!'
        
        resDir = self._dbbResDir.GetValue().replace('/', '\\')
        if not resDir.endswith('\\'):
            resDir += '\\'
            
        if not resDir:
            return u'Resource directory is empty!'
        
        modelDir = self._dbbModelDir.GetValue().replace('/', '\\')
        if not modelDir.endswith('\\'):
            modelDir += '\\'
            
        if not modelDir.startswith(resDir):
            return u'Model directory is not a sub directory of resource directory!'
            
        meshDir = self._dbbMeshDir.GetValue().replace('/', '\\')
        if not meshDir.endswith('\\'):
            meshDir += '\\'
            
        if not meshDir.startswith(resDir):
            return u'Mesh directory is not a sub directory of resource directory!'
            
        aniDir = self._dbbAniDir.GetValue().replace('/', '\\')          
        if not aniDir.endswith('\\'):
            aniDir += '\\'
            
        if not aniDir.startswith(resDir):
            return u'Animation directory is not a sub directory of resource directory!'
        
        return None
        
    def __OnBnExportClick(self, e):
        errorMsg = self.__CheckSetting()
        if errorMsg != None:
            dlg = GMD.GenericMessageDialog(self, errorMsg, u'Error', wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return
                    
        wildcard = 'MK3DE xml model file(*.model.xml)|*.model.xml|All files (*.*)|*.*'
        dlg = wx.FileDialog(
            self, message = u'Save file as ...', defaultDir = GLOBAL_SETTING._resourceDir,
            wildcard = wildcard, style = wx.SAVE)
        
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            CONVERTER.ExportModel(path)
        
        dlg.Destroy()       
        
    def UpdateUI(self):
        self._dbbResDir.SetValue(GLOBAL_SETTING._resourceDir)
        self._dbbModelDir.SetValue(GLOBAL_SETTING._modelDir)
        self._dbbMeshDir.SetValue(GLOBAL_SETTING._meshDir)
        self._dbbMtlDir.SetValue(GLOBAL_SETTING._materialDir)
        self._dbbAniDir.SetValue(GLOBAL_SETTING._animationDir)
        self._dbbTextureDir.SetValue(GLOBAL_SETTING._textureDir)
        
    def OnDropIGameFileList(self, fileList):
        for f in fileList:
            if self._listIGameXML.FindItem(0, f) == -1:
                self._listIGameXML.InsertStringItem(self._listIGameXML.GetItemCount(), f)
            
    def __OnListKeyDown(self, e):
        obj = e.GetEventObject()
        keyCode = e.GetKeyCode()
        if keyCode == wx.WXK_DELETE:        
            while True:
                selected = obj.GetNextItem(-1, state = wx.LIST_STATE_SELECTED)
                if selected == -1:
                    break
                    
                obj.DeleteItem(selected)